using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
using System.Collections.Generic;

public class Account
{
    private int accountId;
    private string accountGuid;
    private string title;
    private string code;
    private AccountType types;
    private string currency;
    private DateTime createDate;
    private DateTime updateDate;
    private decimal clientCredits;
    private decimal clientPayments;
    private decimal clientCharges;
    private decimal clientCreditsToday;
    private decimal clientPaymentsToday;
    private decimal clientChargesToday;

    public int AccountId
    {
        get { return accountId; }
        set { accountId = value; }
    }

    public string AccountGuid
    {
        get { return accountGuid; }
        set { accountGuid = value; }
    }

    public string Title
    {
        get { return title; }
        set { title = value; }
    }

    public string Code
    {
        get { return code; }
        set { code = value; }
    }

    public AccountType Types
    {
        get { return types; }
        set { types = value; }
    }

    public string Currency
    {
        get { return currency; }
        set { currency = value; }
    }

    public DateTime CreateDate
    {
        get { return createDate; }
        set { createDate = value; }
    }

    public DateTime UpdateDate
    {
        get { return updateDate; }
        set { updateDate = value; }
    }

    public decimal ClientCredits
    {
        get { return clientCredits; }
        set { clientCredits = value; }
    }

    public decimal ClientPayments
    {
        get { return clientPayments; }
        set { clientPayments = value; }
    }

    public decimal ClientCharges
    {
        get { return clientCharges; }
        set { clientCharges = value; }
    }

    public decimal ClientCreditsToday
    {
        get { return clientCreditsToday; }
        set { clientCreditsToday = value; }
    }

    public decimal ClientPaymentsToday
    {
        get { return clientPaymentsToday; }
        set { clientPaymentsToday = value; }
    }

    public decimal ClientChargesToday
    {
        get { return clientChargesToday; }
        set { clientChargesToday = value; }
    }

    /// <summary>
    /// Parameterless constructor for serialization.
    /// </summary>
    public Account() { }

    protected Account(
        int accountId,
        string accountGuid,
        string title, 
        string code,
        AccountType types,
        string currency,
        DateTime createDate, 
        DateTime updateDate)
    {
        this.accountId = accountId;
        this.accountGuid = accountGuid;
        this.title = title;
        this.code = code;
        this.types = types;
        this.currency = currency;
        this.createDate = createDate;
        this.updateDate = updateDate;
    }

    protected Account(
        int accountId,
        string accountGuid,
        string title,
        string code,
        AccountType types,
        string currency,
        DateTime createDate,
        DateTime updateDate,
        decimal clientPayments,
        decimal clientCredits,
        decimal clientCharges,
        decimal clientPaymentsToday,
        decimal clientCreditsToday,
        decimal clientChargesToday)
        : this(accountId, accountGuid, title, code, types, currency, createDate, updateDate)
    {
        this.clientPayments = clientPayments;
        this.clientCredits = clientCredits;
        this.clientCharges = clientCharges;
        this.clientPaymentsToday = clientPaymentsToday;
        this.clientCreditsToday = clientCreditsToday;
        this.clientChargesToday = clientChargesToday;
    }

    public static bool CheckCodeExists(string code)
    {
        bool codeExists = false;
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("AccountFetchByCode", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddWithValue("code", code);

            connection.Open();

            SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow);
            if (reader.Read())
            {
                codeExists = true;
            }

            connection.Close();
        }
        return codeExists;
    }

    public static Account Create(string title, string code, AccountType types, string currency)
    {
        int accountId;
        string guid = Guid.NewGuid().ToString();

        if (string.IsNullOrEmpty(title))
        {
            throw new ArgumentNullException("title");
        }

        if (string.IsNullOrEmpty(code))
        {
            throw new ArgumentNullException("code");
        }

        if (string.IsNullOrEmpty(currency))
        {
            throw new ArgumentNullException("currency");
        }

        if (types == 0)
        {
            throw new ArgumentOutOfRangeException("types");
        }

        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("AccountCreate", connection);
            command.CommandType = CommandType.StoredProcedure;

            command.Parameters.AddWithValue("title", title);
            command.Parameters.AddWithValue("code", code);
            command.Parameters.AddWithValue("typeFlags", types);
            command.Parameters.AddWithValue("guid", guid);
            command.Parameters.AddWithValue("currency", currency);

            command.Parameters.Add("accountId", SqlDbType.Int).Direction = ParameterDirection.Output;

            connection.Open();
            command.ExecuteNonQuery();
            connection.Close();

            accountId = (int)command.Parameters["accountId"].Value;
        }

        return new Account(accountId, guid, title, code, types, currency, DateTime.Now, DateTime.Now);
    }

    public static Account Fetch(int accountId)
    {
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("AccountFetchById", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddWithValue("accountId", accountId);

            connection.Open();

            SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow);
            reader.Read();

            Account account = new Account(
                (int)reader["AccountId"],
                (string)reader["Guid"],
                (string)reader["Title"],
                (string)reader["Code"],
                (AccountType)reader["TypeFlags"],
                (string)reader["Currency"],
                (DateTime)reader["CreateDate"],
                (DateTime)reader["UpdateDate"],
                (decimal)reader["ClientPayments"],
                (decimal)reader["ClientCredits"],
                (decimal)reader["ClientCharges"],
                (decimal)reader["ClientPaymentsToday"],
                (decimal)reader["ClientCreditsToday"],
                (decimal)reader["ClientChargesToday"]);

            connection.Close();

            return account;
        }
    }

    public static List<Account> Fetch(AccountType types)
    {
        List<Account> accountList = new List<Account>();
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("AccountFetch", connection);
            command.CommandType = CommandType.StoredProcedure;

            connection.Open();

            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                AccountType testType = (AccountType)reader["typeFlags"];
                if ((testType & types) != 0)
                {
                    Account account = new Account(
                        (int)reader["AccountId"],
                        (string)reader["Guid"],
                        (string)reader["Title"],
                        (string)reader["Code"],
                        (AccountType)reader["TypeFlags"],
                        (string)reader["Currency"],
                        (DateTime)reader["CreateDate"],
                        (DateTime)reader["UpdateDate"],
                        (decimal)reader["ClientPayments"],
                        (decimal)reader["ClientCredits"],
                        (decimal)reader["ClientCharges"],
                        (decimal)reader["ClientPaymentsToday"],
                        (decimal)reader["ClientCreditsToday"],
                        (decimal)reader["ClientChargesToday"]);

                    accountList.Add(account);
                }
            }

            connection.Close();
        }
        return accountList;
    }

    internal static void UpdateContacts(List<string> guidList, int accountId)
    {
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand clearCommand = new SqlCommand("ContactClearByAccountId", connection);
            clearCommand.CommandType = CommandType.StoredProcedure;
            clearCommand.Parameters.AddWithValue("accountId", accountId);

            SqlCommand createCommand = new SqlCommand("CreateContact", connection);
            createCommand.CommandType = CommandType.StoredProcedure;
            createCommand.Parameters.AddWithValue("accountId", accountId);
            createCommand.Parameters.Add("guid", SqlDbType.NVarChar, 200);
            createCommand.Parameters.Add("contactId", SqlDbType.Int).Direction = ParameterDirection.Output;

            connection.Open();
            
            // First clear all existing contacts.
            clearCommand.ExecuteNonQuery();

            // Then re-add each contact individually.
            foreach (string guid in guidList)
            {
                createCommand.Parameters["guid"].Value = guid;
                createCommand.ExecuteNonQuery();
            }

            connection.Close();
        }
    }

    internal static List<string> FetchContacts(int accountId)
    {
        List<string> guidList = new List<string>();
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("ContactFetchByAccountId", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddWithValue("accountId", accountId);

            connection.Open();
            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                guidList.Add((string)reader["Guid"]);
            }
            connection.Close();
        }
        return guidList;
    }
}
